/* 
	Particle System Used throught the Game
	by Julian Williams
	Feb 27, 2010
*/
#include <SFML/Graphics.hpp>
#include <vector>
#include <map>
#include <assert.h>
#include <fstream>

#include "objects.h"
#include "app.h"
#include "helper.h"
#include "cfg_reader.h"
#include "image_manager.h"


//I HATE including these
#include "Camera.h"
#include "levels.h"

#include "particle_factory.h"


//Particle Array
//std::vector< Objects > Particle_Factory::particles;

using namespace std;


//Static Variables
std::string Particle_Factory::resources_directory;

vector < string > Particle_Factory::List;

list < Particles > Particle_Factory::Type;

asIScriptContext * Particle_Factory::ctxMain;

std::map<std::string, int > Particle_Factory::driverFunctIDs;




int CallParticleFunction(asIScriptContext * Context, Particles &p);




/* Load Particles Files */
bool Particle_Factory::Load(string cfg_location)
{

	cout << "****************************************************************\n";
	cout << "       ********* Setting up Particles... *********              \n\n";

	resources_directory = cfg_location;

		//Grab the Type names
	if(!Setup_List()) 
	{ 
		cout << "Get_TypeList() has FAILED! \nError Code: 1337lol" << endl; 
		return false; 
	}
	cout << "# Different Particle: " << List.size() << endl;

	//Ammo_Types.reserve ( List.size() );

	//max_weapons = 2;
	

	//Loop through and load each Particle Type
	for(int i = 0; i < List.size(); i++)
	{
		cout << "Particle Name: " << List[i] << "\n\n";
			
		string cfg_loc = cfg_location + List[i] + "/";

			//add the Particle to the vector
			Particles a;

			//Grab Script driver
			//a.Get_DriverScript(cfg_loc);
			
			//and Configurations
			if(!a.Get_Config(cfg_loc)) 
			{
				cout << "Particle Type: " << List[i] << " failed to load.\n";
				return false;
			}

			//Load Driver Script id function
			a.DriverFunctionID = aScriptEngine.GetModule()->GetFunctionIdByName(a.Get_Name().c_str());
			if(a.DriverFunctionID < 0)
			{
					a.hasDriver = false;
			}

			cout << "********* " << a.Get_Name() << " has ID # " << a.DriverFunctionID << " **************\n\n";
			//add to type vector
			Type.push_back(a);
	}//end for loop


	//Grab function ID's from the particle script
	/*
	if(!Grab_ScriptIDs())
	{
		return false;
	}
	*/

	cout << "****************************************************************\n";
	return true;
}//Eof



/* Setup the Scripts */
bool Particle_Factory::Grab_ScriptIDs()
{
	


	//Now assign function ID's
	list< Particles >::iterator i;

	for(i = Type.begin(); i != Type.end(); i++)
	{
		i->DriverFunctionID = aScriptEngine.GetModule()->GetFunctionIdByName(i->Get_Name().c_str());
	

		if(i->DriverFunctionID < 0)
		{
			i->hasDriver = false;
		}
		cout << "********* " << i->Get_Name() << " has ID # " << i->DriverFunctionID << " **************\n\n";
	}



	return true;
}//EoF







//Emitter
void Particle_Factory::BaseEmit( Particles &type, sf::Vector2f pos,  sf::Vector2f vel , float angle, int p_count)
{
	for(int i = 0; i < p_count; i++)
	{
		
	
		//Set all the particle properties
		
		type.SetPosition(pos);
		
		//random speed
		type.speed = sf::Randomizer::Random(type.min_speed, type.max_speed);
		
		//Set up and Randomize angle if needed
		type.angle = angle;
		type.angle += sf::Randomizer::Random(-type.spread_angle, type.spread_angle);
		

		type.velocity.x =  vel.x;
		type.velocity.y =  vel.y;

		//Choose blendmode
		switch(type.blend_mode)
		{
			case 0:
				type.SetBlendMode(sf::Blend::Alpha);
				break;
			case 1:
				type.SetBlendMode(sf::Blend::Add);
				break;
			case 2:
				type.SetBlendMode(sf::Blend::Multiply);
				break;
			case 3:
			default:
				type.SetBlendMode(sf::Blend::None);
		}


		//randomize rotation direction
		if(sf::Randomizer::Random(0, 1) == 1)
		{
			type.rotation_amount = -type.rotation_amount;
		}

		type.color = type.startingColor;
		
		//Set image
		type.SetImage( *type.img );

		//sf::Image temp = *p.GetImage();


		//Add particle to the array
		type.Set_State(PS_ACTIVE);

		p_obj.push_back(type);
	}
//	cout << "Size of Particle array: " << p_obj.size() << endl;

}//EoF



//Emitter
void Particle_Factory::Emit( Particles &type, sf::Vector2f pos, float angle,  int p_count)
{
	for(int i = 0; i < p_count; i++)
	{
		
	

		//Get Random offset
		float random_dir = sf::Randomizer::Random(-type.spread_angle, type.spread_angle);

		//Very important direction code!!!!!!!!!
			type.velocity.x =  type.Get_Speed() * cos(-1 * degreesToRadians(angle + random_dir ));
			type.velocity.y = -type.Get_Speed() * sin(degreesToRadians(angle + random_dir));

		
	
		BaseEmit(type, pos, type.velocity, type.angle, 1);

	}
	//Randomize_Colors("exaust_1");
	//cout << "Size of Particle array: " << p_obj.size() << endl;

}//EoF



//Emitter
void Particle_Factory::Emit( Particles &type, sf::Vector2f pos, int p_count)
{


		BaseEmit(type, pos, type.velocity, type.angle, p_count);

	//cout << "Emitter spawned: " << p_obj.size() << " Particles \n";
}//EoF



//Emitter based off of particle name
void Particle_Factory::Emit( string type, sf::Vector2f pos, float angle,  int p_count)
{
	list< Particles >::iterator i;

	 //Loop through the particle Type list
		for(i = Type.begin(); i != Type.end(); i++)
		{
			//Name matched!
			if(i->Get_Name() == type)
			{
				//if p count is == to 0, use particles spawn count
				if(p_count == 0)
				{
					p_count = i->amountPerCycle;
				}
				    Emit(*i, pos, angle, p_count);

					//activate teh emitter
					//BaseEmit(*i, pos, i->velocity, angle, p_count);
				break;
			}
		}
}//EoF



//Emitter based off of particle name
void Particle_Factory::Emit( string type, sf::Vector2f pos, sf::Vector2f vel, float angle,  int p_count)
{
	list< Particles >::iterator i;

	 //Loop through the particle Type list
		for(i = Type.begin(); i != Type.end(); i++)
		{
			//Name matched!
			if(i->Get_Name() == type)
			{
				//if p count is == to 0, use particles spawn count
				if(p_count == 0)
				{
					p_count = i->amountPerCycle;
				}
					//activate teh emitter
					BaseEmit(*i, pos, vel, angle, p_count);
				break;
			}
		}
}//EoF












//Randomize Colors!
void Particle_Factory::Randomize_Colors(string particleType)
{
	list< Particles >::iterator i;

	for(i = p_obj.begin(); i != p_obj.end(); i++)
	{
		if(i->Get_Name() == particleType)
		{
			i->startingColor.r = sf::Randomizer::Random(0, 255);
			i->startingColor.g = sf::Randomizer::Random(0, 255);
			i->startingColor.b = sf::Randomizer::Random(0, 255);

			i->endingColor.r = sf::Randomizer::Random(20, 235);
			i->endingColor.g = sf::Randomizer::Random(20, 235);
			i->endingColor.b = sf::Randomizer::Random(20, 235);

			i->changeRateColor.r = sf::Randomizer::Random(0, 20);
			i->changeRateColor.g = sf::Randomizer::Random(0, 20);
			i->changeRateColor.b = sf::Randomizer::Random(0, 20);
		}


	}//end ov for
}//EoF


	
//Modify Velocity
void Particle_Factory::Modify(sf::Vector2f new_velocity)
{
	list< Particles >::iterator i;

	for(i = p_obj.begin(); i != p_obj.end(); i++)
	{
		i->velocity += new_velocity;
	}

}//EoF


void Particle_Factory::Destroy_Particle(Particles &p)
{
	//p = p_obj.erase(erase(p);
}//EoF




/*
void Particle_Factory::Emit( int type_number, int p_count )
{
	Particles t;
	for(int i = 0; i < p_count; i++)
	{
		

		//Set all the particle properties
		
		//sf::Image temp = *p.GetImage();

		t = Type[type_number];


		//Add particle to the array
		p_obj.push_back(t);
/*
		cout << "Particle Infomation: \n" 
			 <<  p_obj.back().Get_Velocity().x << "  \n"
			 <<  p_obj.back().Get_Velocity().y << "  \n"
			 <<  p_obj.back().GetPosition().x << "  \n"
			 <<  p_obj.back().GetPosition().y << "  \n" << endl;

		

	}//End ov for

//	cout << "Emitter spawned: " << p_obj.size() << " Particles \n";

}//EoF
*/

//Do map collision
void Particle_Factory::Map_Collision(Particles &p)
{
	//Check positions
	sf::Vector2f check_pos[4];

	//the 4 truth bools
	bool isColliding[4] = {false};

	const int radius = 5;

//Set up 4 corner collision test points
	//Top-Left
	check_pos[0].x = p.GetPosition().x - radius;
	check_pos[0].y = p.GetPosition().y - radius;

	//Top-Right
	check_pos[1].x = p.GetPosition().x + radius;
	check_pos[1].y = p.GetPosition().y - radius;

	//Bottom-Left
	check_pos[2].x = p.GetPosition().x - radius;
	check_pos[2].y = p.GetPosition().y + radius;

	//Bottom-Right
	check_pos[3].x = p.GetPosition().x + radius;
	check_pos[3].y = p.GetPosition().y + radius;

	


	//if on screen
	// if(Is_OnScreen())
	// {
		 for(int i = 0; i < 4; i++)
		 {
			// cout << check_pos[i].x << ", " << check_pos[i].y << endl;
			 //Collision check
			if(Map.GetMapBlockInPixels(check_pos[i].x +  Cam.Get_Camera().x,  check_pos[i].y +  Cam.Get_Camera().y)->tl == true)
			{
			//p.velocity.x = -p.velocity.x;// * 0.3;
			//p.velocity.x = -p.velocity.x * 0.3;
			//p.Set_State(PS_DEAD);
				isColliding[i] = true;
			}
			//cout << isColliding[i] << endl;

		 }
		 //cout << "*********************************\n";
// }//is on screen?

		// cout << "************************\n" << endl;

	 //test Left/Right side
	 if(((isColliding[0]) && (isColliding[2])) ||
	    ((isColliding[1]) && (isColliding[3])))
	 {
		 p.velocity.x = -p.velocity.x * 0.4;
		//  p.Set_State(PS_DEAD);
	 //Top/Bottom side
	 }else if(((isColliding[0]) && (isColliding[1])) ||
			  ((isColliding[2]) && (isColliding[3])))
	 {
		// p.Set_State(PS_DEAD);
		 p.velocity.y = -p.velocity.y * 0.4;
	 //if on corner, then DIE
	 }else if((isColliding[0]) || (isColliding[1]) ||
			  (isColliding[2]) || (isColliding[3]))
	 {
		 p.Set_State(PS_DEAD);
	 }
}//EoF


//do Standard Logic
void Particle_Factory::Standard_Logic(Particles &p)
{

	//move Bullets according to it's velocity
			


			 //if a particle goes off screen, get rid of it
			 if( !p.Is_OnScreen() )
			 {
					p.Set_State(PS_DEAD);
			 }else{
				 //Do Map Collision
				 if(p.collision)
				 {
					 Map_Collision(p);
				 }
			 }
		


			//Scroll with Map
			if((Cam.canScroll_Left() ) || (Cam.canScroll_Right() ))
			{
				p.SetX(p.GetPosition().x - Cam.Get_Camera().x );
			}
			if((Cam.canScroll_Down() ) || ( Cam.canScroll_Up() ))
			{

				p.SetY(p.GetPosition().y - Cam.Get_Camera().y );
			}
		
			//Update Colors Obviously
			Update_Colors(p);
		

			switch(p.type)
			{
			case PT_NADES:

				p.velocity.y += Map.gravity * 4;


				break;
			}
			


			//if Life is <= 0, then kill particle, else 
			//count down timer
			if(p.life < -1)
			{
				p.Set_State(PS_DEAD);
			}else{
				p.life -= 200 * App::getInstance().Get_RenderWindow()->GetFrameTime();
			}


        


			 
	//Move teh particle
			p.Move(p.velocity * App::getInstance().Get_RenderWindow()->GetFrameTime());  




	//scale accordingly
			/*
			float scale_mult = 60.545 * App::getInstance().Get_RenderWindow()->GetFrameTime();

			//make framerate independent
			if(p.scale.x != 1)
			{
				p.scale.x *= scale_mult;

			}

			if(p.scale.y != 1)
			{
				p.scale.y *= scale_mult;
			}
			
			//p.scale *= -App::getInstance().Get_RenderWindow()->GetFrameTime();
			*/
			//do the actual scale
			p.Scale( p.scale );
			
		

			//rotate accordingly
			if(p.rotation_amount != 0) 
			{
				p.Rotate_Angle(p.rotation_amount * 100 * App::getInstance().Get_RenderWindow()->GetFrameTime());
			}


			//Call its Script Driver
			if(p.hasDriver)
			{
				//aScriptEngine.CallScriptFunction( ctxMain, p.DriverFunctionID );
				CallParticleFunction(ctxMain, p);
			}

}//EoF










	//Update Particle Mechanics
//*****************************************
//*******************************************
void Particle_Factory::Update_Logic()
{

	list< Particles >::iterator i = p_obj.begin();

	while(i != p_obj.end())
	{
		if(i->Get_State() != PS_DEAD)
		{
			//Standard Update
			Standard_Logic(*i);


			//loop through to the next particle
			i++;

		}else{

			//i->SetColor(sf::Color(0,0,0,255));
			//i->SetPosition(0, 0);
			i = p_obj.erase(i);
			
		}
	}//end ov while
	
}//EoF









//Draw to screen
void Particle_Factory::Draw()
{
	list< Particles >::iterator i;

	for(i = p_obj.begin(); i != p_obj.end(); i++)
	{
		if(i->Get_State() != PS_DEAD)
		{

		//cout << p_obj[i].max_speed << endl;
			App::getInstance().Get_RenderWindow()->Draw( *i );
		}
	}
}//EoF




/* Grab the Weapons List */
bool Particle_Factory::Setup_List()
{

	//Get texture directory
	string List_loc = resources_directory + string("list.cfg");
	string list_name;


	cout << "Getting List from: " << List_loc << endl;


	//Open up Ammo List file
	ifstream List_file(List_loc.c_str());
    
	//if file isn't open, return false
	if(!List_file.is_open()) { return false; }

	do 
	{
		//Read in every line
		getline( List_file, list_name);

		if(list_name == "") { break; }

		List.push_back(list_name);

	} while( !List_file.eof() );

	//save the number of textures 
	//max_weapons = List.size(); (redundent

	//Close file
	List_file.close();

	return true;
}//EoF





//Update Colors

void Particle_Factory::Update_Colors(Particles &p)
{
			float frameRate_Mulitiplier = 100 * App::getInstance().Get_RenderWindow()->GetFrameTime();
	
			//HAndle Red component
			if(p.startingColor.r > p.endingColor.r)
			{
				if(p.color.r * 2 > p.endingColor.r)
				{
					p.color.r -= p.changeRateColor.r  * frameRate_Mulitiplier;
				}
			}else if(p.startingColor.r < p.endingColor.r)
			{
				if(p.color.r * 2 < p.endingColor.r)
				{
					p.color.r += p.changeRateColor.r  * frameRate_Mulitiplier;
				}
			}

			//Bounds check
			if(p.color.r > 255) { p.color.r = 255; }
			if(p.color.r < 0) { p.color.r = 0; }



			//Handle Green Component
			if(p.startingColor.g > p.endingColor.g)
			{
				if(p.color.g * 2 > p.endingColor.g)
				{
					p.color.g -= p.changeRateColor.g  * frameRate_Mulitiplier;
				}
			}else if(p.startingColor.g < p.endingColor.g)
			{
				if(p.color.g * 2< p.endingColor.g)
				{
					p.color.g += p.changeRateColor.g  * frameRate_Mulitiplier;
				}
			}
			//Bounds check
			if(p.color.g > 255) { p.color.g = 255; }
			if(p.color.g < 0) { p.color.g = 0; }


			//Handle Blue Component
			if(p.startingColor.b > p.endingColor.b)
			{
				if(p.color.b * 2 > p.endingColor.b)
				{
					p.color.b -= p.changeRateColor.b  * frameRate_Mulitiplier;
				}
			}else if(p.startingColor.b < p.endingColor.b)
			{
				if(p.color.b * 2 < p.endingColor.b)
				{
					p.color.b += p.changeRateColor.b  * frameRate_Mulitiplier;
				}
			}
			//Bounds check
			if(p.color.b > 255) { p.color.b = 255; }
			if(p.color.b < 0) { p.color.b = 0; }



			int temp = p.color.a;

			//Handle Alpha Component
			if(p.startingColor.a > p.endingColor.a)
			{
				if(p.color.a * 2 > p.endingColor.a)
				{
					//Since SFML uses TINY 8 bit ints to represent
					//it's colors, I have to do this HACK to ensure colors,
					//Dont go below 0, and set itself to 255 or vise-versa,
					//if(temp -= p.changeRateColor.a < 0) { p.Set_State(PS_DEAD); }
					p.color.a -= p.changeRateColor.a * frameRate_Mulitiplier;
				}
			}else if(p.startingColor.a < p.endingColor.a)
			{
				if(p.color.a * 2 < p.endingColor.a)
				{
					//Since SFML uses TINY 8 bit ints to represent
					//it's colors, I have to do this HACK to ensure colors,
					//Dont go below 0, and set itself to 255 or vise-versa, KIll the color.
					//if(temp += p.changeRateColor.a > 255) { p.Set_State(PS_DEAD); };
					p.color.a += p.changeRateColor.a * frameRate_Mulitiplier; //increase the actual color

				}
			}
			//Bounds check
			if(p.color.a > 255) { p.color.a = 255; }
			if(p.color.a < 0) { p.color.a = 0; }


			//Set Color, duh!
			p.SetColor(p.color);

}//EoF









//PARICLES CLASS//
//**************//


Particles::Particles()
{
	refCount = 1;
	hasDriver = true;
}

Particles::~Particles()
{
//	assert( refCount == 0 );
}

//--------------------
// reference counting
//--------------------

void Particles::AddRef()
{
	refCount++;
}



void Particles::Release()
{
	if( --refCount == 0 )
		delete this;
}


//-----------------------
// AngelScript functions
//-----------------------

static void ParticlesDefaultFactory(Particles *self)
{
	new(self) Particles();
}


static int CallParticleFunction(asIScriptContext * Context, Particles &p)
{
		int r = -1;

			Context->Prepare( p.DriverFunctionID );

			Context->SetArgObject(0, &p);

			r = Context->Execute();

		if( r != asEXECUTION_FINISHED )
		{
			// The execution didn't finish as we had planned. Determine why.
			if( r == asEXECUTION_ABORTED )
				cout << "The script was aborted before it could finish. Probably it timed out." << endl;
			else if( r == asEXECUTION_EXCEPTION )
			{
				cout << "The script ended with an exception." << endl;

				// Write some information about the script exception
				int funcID = Context->GetExceptionFunction();
				asIScriptFunction *func = aScriptEngine.GetEngine()->GetFunctionDescriptorById(funcID);
				cout << "func: " << func->GetDeclaration() << endl;
				cout << "modl: " << func->GetModuleName() << endl;
				cout << "sect: " << func->GetScriptSectionName() << endl;
				cout << "line: " << Context->GetExceptionLineNumber() << endl;
				cout << "desc: " << Context->GetExceptionString() << endl;
			}
			else
			{
				cout << "The script ended for some unforeseen reason (" << r << ")." << endl;
			}
	  }
		return r;
}//EoF




//Register the Class interface
bool Particles::Register_With_ScriptEngine( string script_dir )
{
	
	int r;

	

	// Register the type
	r = aScriptEngine.GetEngine()->RegisterObjectType("Particles", 0, asOBJ_REF); assert( r >= 0 );

	// Register the object operator overloads
	// Note: We don't have to register the destructor, since the object uses reference counting
	r = aScriptEngine.GetEngine()->RegisterObjectBehaviour("Particles", asBEHAVE_FACTORY, "Particles @f()", asFUNCTION(ParticlesDefaultFactory), asCALL_CDECL); assert( r >= 0 );
	//r = engine->RegisterObjectBehaviour("string", asBEHAVE_FACTORY,    "string @f(const string &in)", asFUNCTION(StringCopyFactory), asCALL_CDECL); assert( r >= 0 );
	r = aScriptEngine.GetEngine()->RegisterObjectBehaviour("Particles", asBEHAVE_ADDREF,  "void f()", asMETHOD(Particles, AddRef),  asCALL_THISCALL); assert( r >= 0 );
	r = aScriptEngine.GetEngine()->RegisterObjectBehaviour("Particles", asBEHAVE_RELEASE, "void f()", asMETHOD(Particles, Release), asCALL_THISCALL); assert( r >= 0 );


	// Register the object methods
		r = aScriptEngine.GetEngine()->RegisterObjectMethod("Particles", "void Move(float, float)", asMETHODPR(Particles, Move,(float, float), void), asCALL_THISCALL); assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterObjectMethod("Particles", "void Rotate(float)", asMETHODPR(Particles, Rotate_Angle,(float), void), asCALL_THISCALL); assert( r >= 0 );
		
	//Register Properties
		r = aScriptEngine.GetEngine()->RegisterObjectProperty("Particles", "float velocity_x",		offsetof(Particles, velocity.x));		assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterObjectProperty("Particles", "float velocity_y",		offsetof(Particles, velocity.y));		assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterObjectProperty("Particles", "float position_x",		offsetof(Particles, GetPosition().x));	assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterObjectProperty("Particles", "float position_y",		offsetof(Particles, GetPosition().y));	assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterObjectProperty("Particles", "float angle",			offsetof(Particles, angle));			assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterObjectProperty("Particles", "float spread_angle",	offsetof(Particles, spread_angle));		assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterObjectProperty("Particles", "int min_speed",			offsetof(Particles, min_speed));		assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterObjectProperty("Particles", "int max_speed",			offsetof(Particles, max_speed));		assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterObjectProperty("Particles", "int damage",			offsetof(Particles, damage));			assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterObjectProperty("Particles", "int life",				offsetof(Particles, life));				assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterObjectProperty("Particles", "int rotation_amount",	offsetof(Particles, rotation_amount));	assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterObjectProperty("Particles", "int type",				offsetof(Particles, type));				assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterObjectProperty("Particles", "bool collision",		offsetof(Particles, collision));		assert( r >= 0 );
		
		//Register enums

		r = aScriptEngine.GetEngine()->RegisterEnum("Particle_State"); assert( r >= 0 );
		int enum_index = 0;
		r = aScriptEngine.GetEngine()->RegisterEnumValue("Particle_State", "PS_NONE", 0 ); assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterEnumValue("Particle_State", "PS_ACTIVE", 1 ); assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterEnumValue("Particle_State", "PS_DEAD", 2 ); assert( r >= 0 );

		r = aScriptEngine.GetEngine()->RegisterEnum("Particle_Type"); assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterEnumValue("Particle_Type", "PT_NONE", 0 ); assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterEnumValue("Particle_Type", "PT_PROJECTILE", 1 ); assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterEnumValue("Particle_Type", "PT_NADES", 2 ); assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterEnumValue("Particle_Type", "PT_SLUGS", 3 ); assert( r >= 0 );
		r = aScriptEngine.GetEngine()->RegisterEnumValue("Particle_Type", "PT_MISSLES", 4 ); assert( r >= 0 );

		// TODO: Add factory  string(const string &in str, int repeatCount)

	// TODO: Add explicit type conversion via constructor and value cast

	// TODO: Add parseInt and parseDouble. Two versions, one without parameter, one with an outparm that returns the number of characters parsed.
		
		
		if(!Get_DriverScript(script_dir + "particle_drivers.as"))
		{
			cout << "Particle Driver Script failed to load." << endl;
		}
		if(r < 0)
		{
			cout << "Register Class Result: " << r << endl;
			return false;
		}

	return true;
}//EoF





/* Get the Ammo Configuration file and load properties */
bool Particles::Get_Config(string resource_dir)
{
	//grab and create the nessisary directories
	string image_location = resource_dir + string("image.png");
	string cfg_location = resource_dir + string("properties.ppf");
	//string snd_location = folder_location + string("fire.wav");

	cout << "Loading Particle folder: " << resource_dir << endl;
	cout << "Config from: " << cfg_location << endl;
	//cout << "Gun sound from: " << snd_location << endl;



//Now Grab the firing sound for the gun
	//if(!Load_Sounds(s_fire, SND_fire, snd_location)) { return false; }




//Grab particle Config
		cfg_reader cfg(cfg_location, false);


//Get all of the properties
	    

		name = cfg.Get_Info("info:name", "Default");

		damage = cfg.Get_Info("info:damage", 10);

		type = cfg.Get_Info("info:type", 0);
		life = cfg.Get_Info("info:life", 100);

		max_speed = cfg.Get_Info("info:max_speed", 1000);
		min_speed = cfg.Get_Info("info:min_speed", 100);

		scale.x = cfg.Get_Info("info:x_scale_factor", 1.05);
		scale.y = cfg.Get_Info("info:y_scale_factor", 1.05);

		rotation_amount = cfg.Get_Info("info:rotation_amount", 0);

		amountPerCycle =  cfg.Get_Info("info:amount_per_cycle", 1);
		spread_angle =  cfg.Get_Info("info:spread_angle", 0);

		//Set speed from random inbetween range
		speed = sf::Randomizer::Random(min_speed, max_speed);
		//use_image = iniparser_getboolean(ini, "ammo:use_image", 0);
		/*
		cout << "Name: " << name << endl;
		cout << "Damage: " << damage << endl;
		cout << "Max Speed: " << max_speed << endl;
		cout << "Min Speed: " << min_speed << endl;
		cout << "X Scale: " << scale.x << endl;
		cout << "Y Scale: " << scale.y << endl;
		cout << "Type: " << type << endl;
		cout << "Life: " << life << endl;
		cout << "Rotation Amount: " << rotation_amount << endl;
		cout << "Spread Angle: " << spread_angle << endl;
		cout << "Particles Per Cycle: " << amountPerCycle << endl;

		*/

		//color properties
		startingColor.r = cfg.Get_Info("color:starting_red", sf::Randomizer::Random(0, 255));
		startingColor.g = cfg.Get_Info("color:starting_green", sf::Randomizer::Random(0, 255));
		startingColor.b = cfg.Get_Info("color:starting_blue", sf::Randomizer::Random(0, 255));
		startingColor.a = cfg.Get_Info("color:starting_alpha", sf::Randomizer::Random(220, 255));

		endingColor.r = cfg.Get_Info("color:ending_red",sf::Randomizer::Random(0, 255));
		endingColor.g = cfg.Get_Info("color:ending_green", sf::Randomizer::Random(0, 255));
		endingColor.b = cfg.Get_Info("color:ending_blue", sf::Randomizer::Random(0, 255));
		endingColor.a = cfg.Get_Info("color:ending_alpha", sf::Randomizer::Random(0, 100));

		changeRateColor.r = cfg.Get_Info("color:rate_of_change_red", sf::Randomizer::Random(0, 30));
		changeRateColor.g = cfg.Get_Info("color:rate_of_change_green", sf::Randomizer::Random(0, 30));
		changeRateColor.b = cfg.Get_Info("color:rate_of_change_blue",sf::Randomizer::Random(0, 30));
		changeRateColor.a = cfg.Get_Info("color:rate_of_change_alpha", sf::Randomizer::Random(4, 30));
		/*
//		cout << "Use Image: " << use_image << endl;
		cout << "Starting Red value: " << static_cast<int>(startingColor.r) << endl;
		cout << "Starting Green value: " << static_cast<int>(startingColor.g) << endl;
		cout << "Starting Blue value: " << static_cast<int>(startingColor.b) << endl;
		cout << "Starting Alpha value: " << static_cast<int>(startingColor.a) << endl;

		cout << "Ending Red value: " << static_cast<int>(endingColor.r) << endl;
		cout << "Ending Green value: " << static_cast<int>(endingColor.g) << endl;
		cout << "Ending Blue value: " << static_cast<int>(endingColor.b) << endl;
		cout << "Ending Alpha value: " << static_cast<int>(endingColor.a) << endl;

		cout << "Changing Red value: " << static_cast<int>(changeRateColor.r) << endl;
		cout << "Changing Green value: " << static_cast<int>(changeRateColor.g) << endl;
		cout << "Changing Blue value: " << static_cast<int>(changeRateColor.b) << endl;
		cout << "Changing Alpha value: " << static_cast<int>(changeRateColor.a) << endl;
		*/
		color = startingColor;
	
		
		//Animation related information
		
			tile_size.x = cfg.Get_Info("animation:tile_width", 100);
			tile_size.y = cfg.Get_Info("animation:tile_height", 50);
			blend_mode = cfg.Get_Info("animation:blend_mode", 0);
			/*
			cout << "Tile Size.X: " << tile_size.x << endl;
			cout << "Tile Size.Y: " << tile_size.y << endl;
			cout << "Blend Mode: " << blend_mode << endl;
			*/

			collision = cfg.Get_Info("Editor:is_collidable", false);
			//cout << "Collision: " << collision << endl;

			//pivit_point.x = CFG_ReadInt("pivit_point_x", 18);
			//pivit_point.y = CFG_ReadInt("pivit_point_y", 20);

			//cout << "Pivit Point.X: " << pivit_point.x << endl;
			//cout << "Pivit Point.Y: " << pivit_point.y << endl;
/*
			shootFrame.start = CFG_ReadInt("shoot_start", 3);
			shootFrame.end = CFG_ReadInt("shoot_end", 4);
			shootFrame.speed = CFG_ReadFloat("shoot_frame_speed", 0);

			fire_delay = CFG_ReadFloat("fire_delay", 1);

			cout << "ShootFrame Start: " << shootFrame.start << ", ShootFrame End: " << shootFrame.end << ", shootFrame Speed: " << shootFrame.speed << "\n\n";
			*/


		
			SetOrigin(sf::Vector2f(tile_size.x/2, tile_size.y/2));

	
			//cout << "Particle Image from: " << image_location << "\n\n";

			//Load Particle Image used for each type
			img = gImageManager.getResource( image_location );
			if(img == NULL) { return false; }
			/*
			if(!Load_Image(image_location)) 
			{
				cout << "Image from - " << image_location << " - failed to load \n";

				return false; 
			}
			*/
	
			
	return true;
}//EoF



/* Get Driver Script that controls particles' Action */
bool Particles::Get_DriverScript(string script_location )
{
	//string script_location = resources_dir + string("driver.as");

	cout << "Loading Script File From: " << script_location << endl;

	// Load weapons script file
	if (aScriptEngine.AddSectionFromFile(script_location.c_str()) < 0)
	{
		//aScriptEngine.Destroy();
		cout << "Failed to load script file." << endl;
	//	hasDriver = false;

		return false;
	}

	return true;
}//EoF
